/**
 * Created on May 9, 2007
 */
package jvs.vfs;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import x.java.io.File;

/**
 * @author qiangli
 * 
 */
public class Fstab implements java.io.Serializable {
	private static final long serialVersionUID = 1L;
	
	private List<Entry> entries = new ArrayList<Entry> ();
	
	public static class Entry {
		public String mountpoint;

		public URI uri;

		public String options;

		private boolean canRead;

		private boolean canWrite;
		
		private String[] optionArray;

		public Entry(String mp, URI uri, String options) {
			this.mountpoint = mp;
			this.uri = uri;
			this.options = options;
			this.optionArray = parseOptions(options);
			this.canRead = (matchOption(optionArray,"r")||matchOption(optionArray,"rw"));
			this.canWrite = (matchOption(optionArray,"w")||matchOption(optionArray,"rw"));
		}

		public Entry() {
		}

		public String getMountpoint() {
			return this.mountpoint;
		}

		public void setMountpoint(String mountpoint) {
			this.mountpoint = mountpoint;
		}

		private static String[] parseOptions(String options) {
			if (options == null || options.length() == 0) {
				return new String[]{"r"};
			}
			StringTokenizer st = new StringTokenizer(options,", \t\r\n");
			String[] sa = new String[st.countTokens()];
			for (int i=0; i<sa.length; i++) {
				sa[i] = st.nextToken();
			}
			return sa;
		}
		
		private static boolean matchOption(String[] options, String opt) {
			for (int i=0; i<options.length; i++) {
				if (options[i].equals(opt)) {
					return true;
				}
			}
			return false;
		}
		
		public boolean canRead() {
			return canRead;
		}
		
		public boolean canWrite() {
			return canWrite;
		}
		
		public String getOptions() {
			return this.options;
		}

		public void setOptions(String options) {
			this.options = options;
			//
			this.optionArray = parseOptions(options);
			this.canRead = (matchOption(optionArray,"r")||matchOption(optionArray,"rw"));
			this.canWrite = (matchOption(optionArray,"w")||matchOption(optionArray,"rw"));
		}

		public URI getUri() {
			return this.uri;
		}

		public void setUri(URI uri) {
			this.uri = uri;
		}

		public String[] optionArray() {
			return this.optionArray;
		}

		public String toString() {
			return mountpoint + " " + uri + " "
					+ (options == null ? "" : options);
		}
	}

	public void add(Entry e) {
		entries.add(e);
	}
	
	public Iterator<Entry> iterator() {
		return entries.iterator();
	}
	
	public static Fstab parse(String url) {
		InputStream is = null;
		try {
			URL u = new URL(url);
			is = u.openStream();
			return parse(new InputStreamReader(is));
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				is.close();
			} catch (IOException e) {

			}
		}
		return null;
	}

	public static Fstab parse(Reader rd) {
		Fstab fst = new Fstab();
		try {
			String str = null;
			BufferedReader br = new BufferedReader(rd, File.BUFSIZE);
			while ((str = br.readLine()) != null) {
				try {
					str = str.trim();
					if (str.length() == 0) {
						continue;
					}
					int idx = str.indexOf("#");
					if (idx == 0) {
						continue;
					}
					if (idx > 0) {
						str = str.substring(0,idx);
					}
					
					StringTokenizer st = new StringTokenizer(str, " \t\r\n");
					Entry fe = new Entry();
					int cnt = st.countTokens();
					if (cnt < 2) {
						continue;
					}
					String base = st.nextToken().trim();
					if (base.startsWith("v:/")) {
						base = base.substring(2);
					}
					fe.setMountpoint(base);

					fe.setUri(new URI(st.nextToken().trim()));
					fe.setOptions(cnt <3 ? "r":st.nextToken("\r\n").trim());
					fst.add(fe);
				} catch (Exception e) {
					e.printStackTrace();
					
				}
			}
			br.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return fst;
	}
}
